
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "SampleCode.h"
#include "SkView.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
#include "SkPackBits.h"
#include "SkPath.h"
#include "SkPathMeasure.h"
#include "SkRandom.h"
#include "SkRegion.h"
#include "SkShader.h"
#include "SkUtils.h"
#include "SkColorPriv.h"
#include "SkColorFilter.h"
#include "SkTypeface.h"
#include "SkAvoidXfermode.h"

#define REPEAT_COUNT    0

static const char gText[] = "Hamburgefons";

static bool gDevKern;

static void rand_text(char text[], SkRandom& rand, size_t count)
    {
    for (size_t i = 0; i < count; i++)
        {
        text[i] = rand.nextU() & 0x7F;
        }
    }

static SkScalar sum_widths(const SkScalar widths[], int count)
    {
    SkScalar w = 0;
    for (int i = 0; i < count; i++)
        {
        w += widths[i];
        }
    return w;
    }

static void test_measure(const SkPaint& paint)
    {
    char        text[256];
    SkScalar    widths[256];
    SkRect      rects[256];
    SkRect      bounds;
    int         count = 256;

    SkRandom rand;

    for (int i = 0; i < 100; i++)
        {
        rand_text(text, rand, 256);
        paint.getTextWidths(text, count, widths, NULL);
        SkDEBUGCODE(SkScalar tw0 = sum_widths(widths, count);)
        paint.getTextWidths(text, count, widths, rects);
        SkDEBUGCODE(SkScalar tw1 = sum_widths(widths, count);)
        SkASSERT(tw0 == tw1);

        SkDEBUGCODE(SkScalar w0 = paint.measureText(text, count, NULL);)
        SkDEBUGCODE(SkScalar w1 = paint.measureText(text, count, &bounds);)
        SkASSERT(w0 == w1);
        SkASSERT(w0 == tw0);

        SkRect r = rects[0];
        SkScalar x = 0;
        for (int j = 1; j < count; j++)
            {
            x += widths[j-1];
            rects[j].offset(x, 0);
            r.join(rects[j]);
            }
        SkASSERT(r == bounds);

        if (r != bounds)
            {
            printf("flags=%x i=%d [%g %g %g %g] [%g %g %g %g]\n",
                   paint.getFlags(), i,
                   SkScalarToFloat(r.fLeft),
                   SkScalarToFloat(r.fTop),
                   SkScalarToFloat(r.fRight),
                   SkScalarToFloat(r.fBottom),
                   SkScalarToFloat(bounds.fLeft),
                   SkScalarToFloat(bounds.fTop),
                   SkScalarToFloat(bounds.fRight),
                   SkScalarToFloat(bounds.fBottom));
            }
        }
    }

static void test_measure()
    {
    SkPaint paint;

    for (int i = 0; i <= SkPaint::kAllFlags; i++)
        {
        paint.setFlags(i);
        test_measure(paint);
        }
    }

//////////////////////////////////////////////////////////////////////////////

static void test_textBounds(SkCanvas* canvas)
    {
//    canvas->scale(SK_Scalar1/2, SK_Scalar1/2);

//    canvas->rotate(SkIntToScalar(30));

    gDevKern = !gDevKern;

    SkScalar x = SkIntToScalar(50);
    SkScalar y = SkIntToScalar(150);
    SkScalar w[100];
    SkRect   r[100], bounds;

    SkPaint paint;
    paint.setTextSize(SkIntToScalar(64));
    paint.setAntiAlias(true);
    paint.setDevKernText(gDevKern);

    (void)paint.measureText(gText, strlen(gText), &bounds);
    paint.setColor(SK_ColorGREEN);
    bounds.offset(x, y);
    canvas->drawRect(bounds, paint);

    int count = paint.getTextWidths(gText, strlen(gText), w, r);

    paint.setColor(SK_ColorRED);
    for (int i = 0; i < count; i++)
        {
        r[i].offset(x, y);
        canvas->drawRect(r[i], paint);
        x += w[i];
        }
    x = SkIntToScalar(50);
    paint.setColor(gDevKern ? SK_ColorDKGRAY : SK_ColorBLACK);
    canvas->drawText(gText, strlen(gText), x, y, paint);
    }

static void create_src(SkBitmap* bitmap, SkBitmap::Config config)
    {
    bitmap->setConfig(config, 100, 100);
    bitmap->allocPixels();
    bitmap->eraseColor(0);

    SkCanvas    canvas(*bitmap);
    SkPaint     paint;

    paint.setAntiAlias(true);
    canvas.drawCircle(SkIntToScalar(50), SkIntToScalar(50),
                      SkIntToScalar(50), paint);
    }

static void blur(SkBitmap* dst, const SkBitmap& src, SkScalar radius)
    {
    *dst = src;
    }

static void test_bitmap_blur(SkCanvas* canvas)
    {
    SkBitmap    src, dst;

    create_src(&src, SkBitmap::kARGB_8888_Config);
    blur(&dst, src, SkIntToScalar(4));

    SkPaint paint;

    paint.setColor(SK_ColorRED);

    canvas->drawBitmap(dst, SkIntToScalar(30), SkIntToScalar(60), &paint);
    }

static SkScalar getpathlen(const SkPath& path)
    {
    SkPathMeasure   meas(path, false);
    return meas.getLength();
    }

static void test_textpathmatrix(SkCanvas* canvas)
    {
    SkPaint paint;
    SkPath  path;
    SkMatrix matrix;

    path.moveTo(SkIntToScalar(200), SkIntToScalar(300));
    path.quadTo(SkIntToScalar(400), SkIntToScalar(100),
                SkIntToScalar(600), SkIntToScalar(300));

    paint.setAntiAlias(true);

    paint.setStyle(SkPaint::kStroke_Style);
//   canvas->drawPath(path, paint);
    paint.setStyle(SkPaint::kFill_Style);
    paint.setTextSize(SkIntToScalar(48));
    paint.setTextAlign(SkPaint::kRight_Align);

    const char* text = "Reflection";
    size_t      len = strlen(text);
    SkScalar    pathLen = getpathlen(path);

    canvas->drawTextOnPath(text, len, path, NULL, paint);

    paint.setColor(SK_ColorRED);
    matrix.setScale(-SK_Scalar1, SK_Scalar1);
    matrix.postTranslate(pathLen, 0);
    canvas->drawTextOnPath(text, len, path, &matrix, paint);

    paint.setColor(SK_ColorBLUE);
    matrix.setScale(SK_Scalar1, -SK_Scalar1);
    canvas->drawTextOnPath(text, len, path, &matrix, paint);

    paint.setColor(SK_ColorGREEN);
    matrix.setScale(-SK_Scalar1, -SK_Scalar1);
    matrix.postTranslate(pathLen, 0);
    canvas->drawTextOnPath(text, len, path, &matrix, paint);
    }

class TextOnPathView : public SampleView
    {
    public:
        SkPath      fPath;
        SkScalar    fHOffset;

        TextOnPathView()
            {
            SkRect r;
            r.set(SkIntToScalar(100), SkIntToScalar(100),
                  SkIntToScalar(300), SkIntToScalar(300));
            fPath.addOval(r);
            fPath.offset(SkIntToScalar(200), 0);

            fHOffset = SkIntToScalar(50);
            }

    protected:
        // overrides from SkEventSink
        virtual bool onQuery(SkEvent* evt)
            {
            if (SampleCode::TitleQ(*evt))
                {
                SampleCode::TitleR(evt, "Text On Path");
                return true;
                }
            return this->INHERITED::onQuery(evt);
            }

        virtual void onDrawContent(SkCanvas* canvas)
            {
            SkPaint paint;

            paint.setAntiAlias(true);
            paint.setTextSize(SkIntToScalar(50));

            for (int j = 0; j < REPEAT_COUNT; j++)
                {
                SkScalar x = fHOffset;

                paint.setColor(SK_ColorBLACK);
                canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
                                         x, paint.getTextSize()/2, paint);

                paint.setColor(SK_ColorRED);
                canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
                                         x + SkIntToScalar(50), 0, paint);

                paint.setColor(SK_ColorBLUE);
                canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
                                         x + SkIntToScalar(100), -paint.getTextSize()/2, paint);
                }

            paint.setColor(SK_ColorGREEN);
            paint.setStyle(SkPaint::kStroke_Style);
//        canvas->drawPath(fPath, paint);

            canvas->translate(0, SkIntToScalar(100));
            test_textpathmatrix(canvas);

            if (REPEAT_COUNT > 1)
                this->inval(NULL);
            }

        virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y)
            {
            fHints += 1;
            this->inval(NULL);
            return this->INHERITED::onFindClickHandler(x, y);
            }

        virtual bool onClick(Click* click)
            {
            return this->INHERITED::onClick(click);
            }

    private:
        int fHints;
        typedef SampleView INHERITED;
    };

//////////////////////////////////////////////////////////////////////////////

static SkView* MyFactory()
    {
    return new TextOnPathView;
    }

static SkViewRegister reg(MyFactory);
